package org.zhangxiao.paladin2.admin.cfg;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Service;
import org.zhangxiao.paladin2.admin.AdminBizError;
import org.zhangxiao.paladin2.admin.entity.SysCfg;
import org.zhangxiao.paladin2.admin.mapper.SysCfgMapper;
import org.zhangxiao.paladin2.common.exception.BizException;
import org.zhangxiao.paladin2.common.pojo.ICfg;
import org.zhangxiao.paladin2.common.util.JacksonUtils;
import org.zhangxiao.paladin2.common.util.StrUtils;

import java.util.Hashtable;
import java.util.Optional;

/**
 * <p>
 * 系统配置  服务实现类
 * </p>
 *
 * @author 听风zx
 * @since 2019-05-25
 */
public class SysCfgServiceWithMemoryCache extends ServiceImpl<SysCfgMapper, SysCfg> implements ISysCfgService {

    private final Hashtable<String, Object> cfgStorage = new Hashtable<>();

    @Override
    public <T extends ICfg> T getCfg(Class<T> cfgClass) {
        return getCfg(cfgClass, null);
    }

    @Override
    public <T extends ICfg> T getCfg(Class<T> cfgClass, String subKey) {
        String cfgKey = getCfgDbKey(cfgClass, subKey);
        return getCfgByDbKey(cfgClass, cfgKey);
    }

    @Override
    public <T extends ICfg> void saveCfg(T cfg) throws BizException {
        saveCfg(cfg, null);
    }

    @Override
    public <T extends ICfg> void saveCfg(T cfg, String subKey) throws BizException {
        String cfgKey = getCfgDbKey(cfg.getClass(), subKey);
        if (StrUtils.isEmpty(cfgKey)) {
            throw new BizException(AdminBizError.CONFIG_KEY_INVALID);
        }
        SysCfg config = new SysCfg();
        config.setCfgKey(cfgKey);
        config.setCfgVal(JacksonUtils.toJson(cfg));
        config.insertOrUpdate();
        cfgStorage.remove(getRedisKey(cfgKey));
    }

    @Override
    public <T extends ICfg> void deleteCfg(Class<T> cfgClass) {
        deleteCfg(cfgClass, null);
    }

    @Override
    public <T extends ICfg> void deleteCfg(Class<T> cfgClass, String subKey) {
        String cfgKey = getCfgDbKey(cfgClass, subKey);
        baseMapper.deleteById(cfgKey);
        cfgStorage.remove(getRedisKey(cfgKey));
    }

    @Override
    public <T extends ICfg> void flushCfg(Class<T> cfgClass) {
        flushCfg(cfgClass, null);
    }

    @Override
    public <T extends ICfg> void flushCfg(Class<T> cfgClass, String subKey) {
        String cfgKey = getCfgDbKey(cfgClass, subKey);
        cfgStorage.remove(getRedisKey(cfgKey));
    }

    @Override
    public void flushAll() {
        cfgStorage.clear();
    }


    private <T extends ICfg> T getCfgByDbKey(Class<T> cfgClass, String cfgDbKey) {
        ICfg cfg = (ICfg) cfgStorage.getOrDefault(getRedisKey(cfgDbKey), null);
        if (cfg != null) {
            return (T) cfg;
        }
        String cfgJson = Optional.ofNullable(baseMapper.selectById(cfgDbKey))
                .map(SysCfg::getCfgVal)
                .orElse(null);

        if (cfgJson == null) {
            return null;
        } else {
            cfg = JacksonUtils.fromJson(cfgJson, cfgClass);
            cfgStorage.put(getRedisKey(cfgDbKey), cfg);
            return (T) cfg;
        }
    }

    private String getRedisKey(String dbKey) {
        return CFG_KEY_PREFIX + dbKey;
    }

    private <T extends ICfg> String getCfgDbKey(Class<T> cfgClass, String subKey) {
        String cfgKey = cfgClass.getSimpleName();
        if (!StrUtils.isEmpty(subKey)) {
            cfgKey += "-" + subKey;
        }
        return cfgKey;
    }
}
